package com.zmn.plat.admin.controller.channel;

import com.alibaba.dubbo.config.annotation.Reference;
import com.google.common.collect.Maps;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto.KvDTO;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.common.constant.DpermitConsts;
import com.zmn.mcc.common.dto.dept.DeptDRO;
import com.zmn.mcc.dubbo.interfaces.dept.DeptListRemoteService;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.plat.admin.controller.PlatBaseController;
import com.zmn.plat.business.interfaces.channel.ChannelBService;
import com.zmn.plat.business.interfaces.channel.ChannelCityPriceRatioBService;
import com.zmn.plat.business.interfaces.channel.ChannelCopyBService;
import com.zmn.plat.business.interfaces.channel.ChannelProductMapBService;
import com.zmn.plat.business.interfaces.channel.brand.ratio.ChannelBrandRatioBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.dubbo.utils.DubboConsts;
import com.zmn.plat.manager.dictionary.ChannelDict;
import com.zmn.plat.model.entity.area.BaseArea;
import com.zmn.plat.model.entity.channel.Channel;
import com.zmn.plat.model.entity.company.BaseCompany;
import com.zmn.plat.model.entity.company.BaseCompanyQuery;
import com.zmn.plat.model.entity.product.BaseCodeMap;
import com.zmn.plat.model.entity.product.BaseCodeMapQuery;
import com.zmn.plat.model.entity.servcategory.ServAssCategory;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.servcategory.ServAssCategoryVO;
import com.zmn.plat.services.interfaces.area.BaseAreaService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.*;
import com.zmn.plat.services.interfaces.channel.commission.settle.rule.ChannelCommissionSettleRuleService;
import com.zmn.plat.services.interfaces.channel.generalproduct.ChannelGeneralProductSwitchService;
import com.zmn.plat.services.interfaces.channel.order.config.ChannelOrderConfigService;
import com.zmn.plat.services.interfaces.channel.product.map.ChannelProductMapService;
import com.zmn.plat.services.interfaces.channel.tariff.ChannelTariffService;
import com.zmn.plat.services.interfaces.company.BaseCompanyService;
import com.zmn.plat.services.interfaces.product.BaseCodeMapService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.plat.services.interfaces.service.tariff.ServiceTariffService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 渠道BaseController
 *
 * @author xiangjunming
 * @since 2019 /08/19 19:30:36
 */
public class ChannelBaseController extends PlatBaseController {

    private static Map<String, Integer> sortBaseCode = new HashMap<>();

    private static HashMap<String, String> channelEngineerUriMap = Maps.newHashMap();

    @Value("${spring.profiles.active}")
    private String profiles;

    static {
        sortBaseCode.put("IT行业", 1);
        sortBaseCode.put("信息平台/广告媒体", 2);
        sortBaseCode.put("制造业/厂矿", 3);
        sortBaseCode.put("金融行业", 4);
        sortBaseCode.put("物业", 5);
        sortBaseCode.put("家政行业", 6);
        sortBaseCode.put("房地产", 7);
        sortBaseCode.put("酒店业", 8);
        sortBaseCode.put("政府机关", 9);
        sortBaseCode.put("教育业", 10);
        sortBaseCode.put("餐饮业", 11);
        sortBaseCode.put("搬家/物流", 12);
        sortBaseCode.put("保险业", 13);
        sortBaseCode.put("其他行业", 14);
    }

    static {
        channelEngineerUriMap.put("dev", "http://dev-engineer.xiujiadian.com/channel/servicemaster/list.action");
        channelEngineerUriMap.put("uat", "http://uat-engineer.xiujiadian.com/channel/servicemaster/list.action");
        channelEngineerUriMap.put("pre", "http://pre-engineer.xiujiadian.com/channel/servicemaster/list.action");
        channelEngineerUriMap.put("test", "http://test-engineer.xiujiadian.com/channel/servicemaster/list.action");
        channelEngineerUriMap.put("test2", "http://test2-engineer.xiujiadian.com/channel/servicemaster/list.action");
        channelEngineerUriMap.put("prod", "https://engineer.xiujiadian.com/channel/servicemaster/list.action");
    }

    /**
     * 省parentId
     */
    public static final int AREA_PARENTID = 1;

    public static final char channelDiscountRatioType = '1';
    public static final char channelCityRatioType = '2';
    public static final char channelBrandRatioType = '3';

    /**
     * The Channel new service.
     */
    @Autowired
    protected ChannelService channelService;

    @Resource
    protected ChannelOrderConfigService channelOrderConfigService;

    @Resource
    protected ChannelCommissionSettleRuleService channelCommissionSettleRuleService;

    @Autowired
    protected BaseCompanyService baseCompanyService;

    @Autowired
    protected ChannelLogService channelLogService;

    @Autowired
    protected ChannelGeneralProductSwitchService channelGeneralProductSwitchService;

    @Autowired
    protected ChannelTariffService channelTariffService;

    @Autowired
    protected ChannelServiceCategoryService channelServiceCategoryService;

    @Resource
    protected ChannelCityPriceRatioService cityPriceRatioService;

    @Resource
    protected ChannelCityPriceRatioBService channelCityPriceRatioBService;

    @Resource
    protected ChannelBrandRatioBService channelBrandRatioBService;

    /**
     * The Channel new b service.
     */
    @Autowired
    protected ChannelBService channelBService;

    @Resource
    protected ChannelProductMapBService channelProductMapBService;

    /**
     * The Base area service.
     */
    @Autowired
    protected BaseAreaService baseAreaService;

    /**
     * The Base code map service.
     */
    @Autowired
    protected BaseCodeMapService baseCodeMapService;

    /**
     * The Serv ass category service.
     */
    @Autowired
    protected ServAssCategoryService servAssCategoryService;

    /**
     * The Service category service.
     */
    @Autowired
    protected ChannelServiceCategoryService categoryService;

    @Autowired
    protected ChannelServiceAreaService serviceAreaService;

    /**
     * The Service category service.
     */
    @Autowired
    protected ChannelServiceAreaCategoryService areaCategoryService;

    /**
     * The Commission service.
     */
    @Autowired
    protected ChannelCommissionService commissionService;

    @Autowired
    protected ServCategoryService servCategoryService;

    @Autowired
    protected BaseCategoryService baseCategoryService;

    @Autowired
    protected ServProductService servProductService;

    // @Autowired
    // protected ChannelBasePriceService channelBasePriceService;

    @Autowired
    protected ChannelServProductService channelServProductService;

    @Resource
    protected ChannelProductMapService channelProductMapService;

    @Resource
    protected ChannelCopyBService channelCopyBService;

    @Autowired
    protected ChannelSettleService channelSettleService;

    @Autowired
    protected ChannelDepositService depositService;

    @Autowired
    protected ChannelDepositLogService depositLogService;

    @Autowired
    protected ServiceTariffService faultTariffService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    protected DeptListRemoteService deptListRemoteService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    protected StaffListRemoteService staffListRemoteService;

    /**
     * 根据环境获取渠道服务工程师链接
     *
     * @param channelId
     * @return
     */
    protected String getChannelEngineerUri(Integer channelId, String addFlag) {
        return channelEngineerUriMap.get(profiles) + "?channelId=" + channelId + "&addFlag=" + addFlag;
    }

    /**
     * 获取一级部门
     *
     * @return the one dept list
     */
    @ReadOnlyConnection
    protected List<DeptDRO> getOneDeptList() {
        List<DeptDRO> oneDeptList =
                deptListRemoteService.listDeptByLevelAndStatus(DpermitConsts.DEPT_LEVEL_ONE, GlobalConsts.YES).getData();
        return oneDeptList;
    }

    /**
     * 获取二级部门
     *
     * @return the two dept list
     */
    @ReadOnlyConnection
    protected List<DeptDRO> getTwoDeptList() {
        List<DeptDRO> twoDeptList =
                deptListRemoteService.listDeptByLevelAndStatus(DpermitConsts.DEPT_LEVEL_TWO, GlobalConsts.YES).getData();
        return twoDeptList;
    }

    /**
     * 获取省份列表
     *
     * @return the province list
     */
    @ReadOnlyConnection
    protected List<BaseArea> getProvinceList() {
        return baseAreaService.listByParentId(AREA_PARENTID);
    }

    /**
     * 获取城市列表
     *
     * @return the city list
     */
    @ReadOnlyConnection
    protected List<BaseArea> getCityList() {
        List<Integer> provinceIds = getProvinceList().stream().map(p -> p.getAreaId()).collect(Collectors.toList());
        return baseAreaService.listByParentIds(provinceIds.toArray(new Integer[provinceIds.size()]), null);
    }

    /**
     * 获取一级渠道列表
     *
     * @return the one channels
     */
    @ReadOnlyConnection
    protected List<Channel> getOneChannels() {
        return channelService.listOneLevelChannel();
    }

    /**
     * 获取所属行业列表
     *
     * @return the base code list
     */
    @ReadOnlyConnection
    protected List<BaseCodeMap> getBaseCodeList() {
        BaseCodeMapQuery baseCodeMapQuery = new BaseCodeMapQuery();
        baseCodeMapQuery.setOneTypeId(ChannelDict.BASE_CODE_MAP_ONE_TYPE_INDUSTRY);
        List<BaseCodeMap> baseCodeList = baseCodeMapService.listByQuery(baseCodeMapQuery);
        List<BaseCodeMap> sortList = baseCodeList.stream()
                .sorted(Comparator.comparing(p -> Optional.ofNullable(sortBaseCode.get(p.getName())).orElse(99))).collect(Collectors.toList());
        return sortList;
    }

    /**
     * 获取公司列表
     *
     * @return the base company list
     */
    @ReadOnlyConnection
    protected List<BaseCompany> getBaseCompanyList() {
        BaseCompanyQuery companyQuery = new BaseCompanyQuery();
        companyQuery.setStatus(ChannelDict.STATUS_NORMAL);
        List<BaseCompany> baseCompanieList = baseCompanyService.listByQuery(companyQuery);
        return baseCompanieList;
    }

    protected <T> List<T> getCategoryRatio(Consumer<ServAssCategoryQuery> setQuery, Function<ServAssCategoryVO, T> servCategConvert,
                                           Function<ServAssCategoryVO, T> categOneConvert, Function<ServAssCategoryVO, T> categConvert, BiConsumer<T, List<T>> setChildren) {
        ServAssCategoryQuery categoryQuery = new ServAssCategoryQuery();
        categoryQuery.setCategOneStatus(GlobalConsts.YES);
        categoryQuery.setCategTwoStatus(GlobalConsts.YES);
        setQuery.accept(categoryQuery);

        if (ProductConsts.EC_PRODUCT_TYPE.equals(categoryQuery.getShowType())) {
            categoryQuery.setServCategShowStatus(GlobalConsts.YES);
        } else {
            categoryQuery.setServCategStatus(GlobalConsts.YES);
        }

        List<ServAssCategoryVO> voList = servAssCategoryService.listByQuery(categoryQuery);
        // 按服务分类分组
        Map<Integer, List<ServAssCategoryVO>> serviceCategoryMap = voList.stream().collect(groupingBy(ServAssCategory::getServCategId));

        List<T> ret = serviceCategoryMap.values().stream().map(serviceCategory -> {
            // 按一级分类分组
            Map<Integer, List<ServAssCategoryVO>> categoryOneMap =
                    serviceCategory.stream().collect(groupingBy(ServAssCategory::getCategOneId));

            List<T> categoryOneList = categoryOneMap.values().stream().map(categoryOne -> {
                // 二级分类KvDTO
                List<T> categList = categoryOne.stream().map(categConvert).collect(Collectors.toList());
                // 一级分类KvDTO
                T categOneVO = categOneConvert.apply(categoryOne.get(0));
                setChildren.accept(categOneVO, categList);
                return categOneVO;
            }).collect(Collectors.toList());

            // 服务分类KvDTO
            T servCategVO = servCategConvert.apply(serviceCategory.get(0));
            setChildren.accept(servCategVO, categoryOneList);
            return servCategVO;
        }).collect(Collectors.toList());
        return ret;
    }

    /**
     * 获取全部分类信息
     *
     * @param setQuery showType 产品分类 1后台 2前台
     * @return the list
     */
    @ReadOnlyConnection
    @SuppressWarnings("all")
    protected List<KvDTO<Integer, String>> getAllChildCategory(Consumer<ServAssCategoryQuery> setQuery) {
        ServAssCategoryQuery categoryQuery = new ServAssCategoryQuery();
        categoryQuery.setCategOneStatus(GlobalConsts.YES);
        categoryQuery.setCategTwoStatus(GlobalConsts.YES);
        setQuery.accept(categoryQuery);

        if (ProductConsts.EC_PRODUCT_TYPE.equals(categoryQuery.getShowType())) {
            categoryQuery.setServCategShowStatus(GlobalConsts.YES);
        } else {
            categoryQuery.setServCategStatus(GlobalConsts.YES);
        }

        List<ServAssCategoryVO> voList = servAssCategoryService.listByQuery(categoryQuery);
        // 按服务分类分组
        Map<Integer, List<ServAssCategoryVO>> serviceCategoryMap = voList.stream().collect(groupingBy(ServAssCategory::getServCategId));

        List<KvDTO<Integer, String>> ret = serviceCategoryMap.values().stream().map(serviceCategory -> {
            // 按一级分类分组
            Map<Integer, List<ServAssCategoryVO>> categoryOneMap =
                    serviceCategory.stream().collect(groupingBy(ServAssCategory::getCategOneId));

            List<KvDTO> categoryOneList = categoryOneMap.values().stream().map(categoryOne -> {
                // 二级分类KvDTO
                List<KvDTO> categList =
                        categoryOne.stream().map(p -> new KvDTO(p.getCategId(), p.getCategName())).collect(Collectors.toList());
                // 一级分类KvDTO
                KvDTO categOne = new KvDTO<>(categoryOne.get(0).getCategOneId(), categoryOne.get(0).getCategOneName());
                categOne.setChildren(categList);
                return (KvDTO<Integer, String>) categOne;
            }).collect(Collectors.toList());

            // 服务分类KvDTO
            KvDTO dto = new KvDTO<>(serviceCategory.get(0).getServCategId(), serviceCategory.get(0).getServCategName());
            dto.setChildren(categoryOneList);
            return (KvDTO<Integer, String>) dto;
        }).collect(Collectors.toList());
        return ret;
    }

    /**
     * 获取服务分类
     *
     * @return the list
     */
    @ReadOnlyConnection
    protected List<ServCategory> getServCategoryList() {
        ServCategory query = new ServCategory();
        query.setStatus(GlobalDict.STATUS_ENABLE);
        return servCategoryService.listByQuery(query);
    }

    /**
     * setVOListCompanyName
     *
     * @param source
     */
    protected <T> void setVOListCompanyAttr(List<T> source, Function<T, Integer> getCompanyId, BiConsumer<T, BaseCompany> setAttr) {
        Assert.notNull(source, "list must not be null");
        List<Integer> companyIdList = source.stream().map(getCompanyId).distinct().collect(Collectors.toList());
        Map<Integer, BaseCompany> companyMap = baseCompanyService.findByKeys(companyIdList, null, null, null).stream()
                .collect(Collectors.toMap(item -> item.getCompanyId(), item -> item));
        source.forEach(item -> setAttr.accept(item, companyMap.get(getCompanyId.apply(item))));
    }

    /**
     * setVOListCompanyName
     *
     * @param source
     */
    protected <T> void setVOListAreaAttr(List<T> source, Function<T, Integer> getAreaId, BiConsumer<T, BaseArea> setAttr) {
        Assert.notNull(source, "list must not be null");
        List<Integer> areaIdList = source.stream().map(getAreaId).distinct().collect(Collectors.toList());
        Map<Integer, BaseArea> areaMap =
                baseAreaService.findByKeys(areaIdList).stream().collect(Collectors.toMap(item -> item.getAreaId(), item -> item));
        source.forEach(item -> setAttr.accept(item, areaMap.get(getAreaId.apply(item))));
    }


}